// 简单的命令模式
function setCommand(elem: HTMLElement, command: BasicCommand) {
  elem.addEventListener("click", () => {
    command.execute();
  });
}
// 按钮分块做出的行为-->抽象成了对象
const MenuBar = {
  refresh() {
    console.log("刷新菜单的目录");
  },
};
const SubMenu = {
  add() {
    console.log("增加子菜单");
  },
  del() {
    console.log("删除子菜单");
  },
};
// 基础的命令类
class MenuBarCommand implements BasicCommand {
  protected receiver: any;
  constructor(receiver: any) {
    this.receiver = receiver;
  }
  execute() {
    this.receiver.refresh();
  }
}
class AddSubMenuCommand implements BasicCommand {
  protected receiver: any;
  constructor(receiver: any) {
    this.receiver = receiver;
  }
  execute() {
    this.receiver.add();
  }
}
class DelSubMenuCommand implements BasicCommand {
  protected receiver: any;
  constructor(receiver: any) {
    this.receiver = receiver;
  }
  execute() {
    this.receiver.del();
  }
}

// 测试用例
const btns: NodeListOf<HTMLButtonElement> = document.querySelectorAll("button"); // 按钮集合
// 实例化指令类
const mbCommand = new MenuBarCommand(MenuBar);
const addMenuCommand = new AddSubMenuCommand(SubMenu);
const delMenuCommand = new DelSubMenuCommand(SubMenu);
// 为按钮绑定点击事件并注册指令
btns.forEach((btn) => {
  setCommand(btn, mbCommand);
  setCommand(btn, addMenuCommand);
  setCommand(btn, delMenuCommand);
});

// 使用闭包实现命令模式
function getRefreshCommand(receiver: { refresh(): void }): BasicCommand {
  return {
    execute() {
      receiver.refresh();
    },
  };
}

// 测试用例
const btn1: HTMLButtonElement = document.querySelector(
  "button"
) as HTMLButtonElement;
const refreshCommand = getRefreshCommand(MenuBar);
setCommand(btn1, refreshCommand);

// 小球动画
const ball = document.querySelector(".ball") as HTMLElement;
const pos = document.querySelector("#pos") as HTMLInputElement;
const moveBtn = document.querySelector("#move") as HTMLElement;
// 绑定点击事件
// moveBtn.addEventListener("click", function() {
//   ball.style.transform = `translateX(${pos.value}px)`;
// });

// 使用命令模式进行重构
class MoveCommand implements IMoveCommand {
  receiver: any;
  pos: string;
  previousPos: string;
  el: HTMLElement;
  constructor(receiver: any, pos: string, el: HTMLElement, oldPos = "0") {
    this.receiver = receiver;
    this.pos = pos;
    this.previousPos = oldPos;
    this.el = el;
  }
  execute() {
    // 暴露接口：外部只需管执行就可以了
    this.receiver(this.pos);
    this.previousPos = getComputedStyle(this.el).transform; // 存储当前位置
  }
  undo() {
    //暴露接口：使用上一次存储的位置撤销
    this.receiver(this.previousPos);
  }
}

// 测试案例
const canceLBtn = document.querySelector("#cancel") as HTMLElement;
let globalMoveCommand: IMoveCommand | null = null; // 全局调度指令
// 接受注册的动画函数
function moveAnimate(value: string) {
  ball.style.transform = value;
}
moveBtn.addEventListener("click", function() {
  globalMoveCommand = new MoveCommand(
    moveAnimate,
    `translateX(${pos.value}px)`,
    ball
  );
  globalMoveCommand.execute(); // 执行命令
});
canceLBtn.addEventListener("click", function() {
  globalMoveCommand?.undo(); // 撤销命令
});

// 键盘码映射哈希表
const keyCodeHashMap: StringIndexObject = {
  "119": "w",
  "115": "s",
  "97": "a",
  "100": "d",
};
// 行为对应函数
const activeBehavior = {
  w() {
    alert("大跳！");
  },
  a() {
    alert("后撤！");
  },
  s() {
    alert("下蹲！");
  },
  d() {
    alert("猛冲！");
  },
};
// 生成指令函数-->高阶函数，生成的指令也是函数
function getCommand(receiver: any, userInput: number) {
  return receiver[keyCodeHashMap[userInput]];
}
// 存储指令的栈
const commandStack: any[] = [];

// 测试用例
document.body.addEventListener("keypress", function(event: KeyboardEvent) {
  let keyCode = event.keyCode;
  const currCommand = getCommand(activeBehavior, keyCode);
  if (currCommand) {
    // 如果指令存在
    commandStack.push(currCommand);
    currCommand();
  }
});
// 开始回放所有操作
document.querySelector("#replay")?.addEventListener("click", function() {
  while (commandStack.length > 0) {
    let currCommand = commandStack.shift();
    currCommand();
  }
});

